use std::collections::HashMap;
use std::fs;
use std::path::Path;
use std::sync::OnceLock;

use crate::environment::define;
use crate::index::index;
use crate::runtime::runtime::{error, path};
use crate::runtime::runtime::result::PanicErrorResult;

/// 全局环境
const GLOBAL_ENVIRONMENT_FILENAME: &str = "environment.json";
static mut GLOBAL: OnceLock<define::Environment> = OnceLock::new();

pub fn global() -> &'static define::Environment {
    unsafe {
        GLOBAL.get_or_init(|| {
            // 全局环境文件路径
            let path = Path::new(path::DEM_ROOT_PATH).join(GLOBAL_ENVIRONMENT_FILENAME);
            load_from_json(path.as_path()).expect("读取全局环境配置失败，无法解析配置文件")
        })
    }
}

pub fn global_mut() -> &'static mut define::Environment {
    unsafe {
        let mut value = GLOBAL.get_mut();
        if value.is_none() {
            let _ = global();
            value = GLOBAL.get_mut();
        }

        value.unwrap()
    }
}

/// 项目环境
const PROJECT_ENVIRONMENT_FILENAME: &str = ".dem.json";
static mut PROJECT: OnceLock<define::Environment> = OnceLock::new();

pub fn project() -> &'static define::Environment {
    unsafe {
        PROJECT.get_or_init(|| {
            // 项目环境文件路径
            let path = Path::new(".").join(PROJECT_ENVIRONMENT_FILENAME);
            load_from_json(path.as_path()).expect("读取项目环境配置失败，无法解析配置文件")
        })
    }
}

pub fn project_mut() -> &'static mut define::Environment {
    unsafe {
        let mut value = PROJECT.get_mut();
        if value.is_none() {
            let _ = project();
            value = PROJECT.get_mut();
        }

        value.unwrap()
    }
}

/// 获取配置的软件映射表
pub fn get_project_used_software(project_only: bool) -> HashMap<String, String> {
    let mut software: HashMap<String, String> = HashMap::new();

    if !project_only {
        // 全局
        for (name, version) in global().get_software().iter() {
            software.insert(name.clone(), version.clone());
        }
    }

    // 项目
    for (name, version) in project().get_software().iter() {
        software.insert(name.clone(), version.clone());
    }

    software
}

/// 检查给定软件与版本号是否已安装
pub fn is_installed(name: &str, version: &str) -> bool {
    Path::new(path::DEM_SOFTWARE_PATH).join(name).join(version).join(".installed").exists()
}

/// 返回当前环境（项目、全局）使用的版本号
pub fn get_used_version(name: &str) -> Option<String> {
    let software = project().get_software();
    let version = software.get(name);
    if version.is_some() {
        return Some(version.unwrap().to_string());
    }

    let software = global().get_software();
    let version = software.get(name);
    if version.is_some() {
        return Some(version.unwrap().to_string());
    }

    None
}

/// 命令搜索路径表
pub fn resolve_paths() -> Vec<String> {
    let mut paths: Vec<String> = Vec::new();
    for (name, version) in get_project_used_software(false).iter() {
        let software = index::index().get(name);
        if software.is_none() {
            continue;
        }

        let version = software.unwrap().get_version(version);
        if version.is_none() {
            continue;
        }

        let version = version.unwrap();
        let target = Path::new(path::DEM_SOFTWARE_PATH).join(name).join(version.version.as_str());

        // 搜索路径
        for p in version.paths.iter() {
            paths.push(path::replace_package_tokens(p, target.to_str().unwrap(), version.version.as_str(), None));
        }
    }

    paths
}

/// 从文件加载环境配置
fn load_from_json<P: AsRef<Path>>(path: P) -> PanicErrorResult<define::Environment> {
    let path = path.as_ref();

    let mut environment = define::Environment::new(path);

    if path.exists() {
        let content = fs::read_to_string(path.to_str().unwrap()).map_err(|e| error::PanicError::new(e.to_string()))?;
        environment = serde_json::from_str(content.as_str()).map_err(|e| error::PanicError::new(e.to_string()))?;
        environment.config_path = path.to_str().unwrap().to_string();
    }

    Ok(environment)
}